package com.zh.webflux.config;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import io.shardingjdbc.core.api.config.ShardingRuleConfiguration;
import io.shardingjdbc.core.api.config.TableRuleConfiguration;
import io.shardingjdbc.core.api.config.strategy.StandardShardingStrategyConfiguration;
import io.shardingjdbc.core.jdbc.core.datasource.ShardingDataSource;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * 数据源配置
 */
@Configuration
@MapperScan(basePackages = "com.zh.webflux.dao", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class DataSourceConfig {
	/**
	 * 配置分库分表策略
	 * 
	 * @return
	 * @throws SQLException
	 */
	@Bean(name = "shardingDataSource")
	DataSource getShardingDataSource() throws SQLException {
		ShardingRuleConfiguration shardingRuleConfig;
		shardingRuleConfig = new ShardingRuleConfiguration();
		shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration());
		// 如果有多个表，可以用逗号“,”分隔 ，比如user_info,t_order
		shardingRuleConfig.getBindingTableGroups().add("user_info");
//		shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(
//				new StandardShardingStrategyConfiguration("user_id", DemoDatabaseShardingAlgorithm.class.getName()));
		shardingRuleConfig.setDefaultTableShardingStrategyConfig(
				new StandardShardingStrategyConfiguration("user_id", DemoTableShardingAlgorithm.class.getName()));
		return new ShardingDataSource(shardingRuleConfig.build(createDataSourceMap()));
	}

	/**
	 * 设置表的node
	 * 
	 * @return
	 */
	@Bean
	TableRuleConfiguration getUserTableRuleConfiguration() {
		TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
		// 逻辑表名称:数据分片的逻辑表,对于水平拆分的数据库(表)来说,是同一类表的总称。如:订单数据根据主键尾数拆分为10张表,分表是t
		// order 0到t order 9,他们的逻辑表名为t_order。
		orderTableRuleConfig.setLogicTable("user_info");
		// 源名 + 表名:数据分片的最小单元,由数据源名称和数据表组成。如:ds 1.t order_0。
		orderTableRuleConfig.setActualDataNodes("user_0.user_info_${0..1}");
		// 自增列名称
		orderTableRuleConfig.setKeyGeneratorColumnName("user_id");
		return orderTableRuleConfig;
	}

	/**
	 * 需要手动配置事务管理器
	 *
	 * @param shardingDataSource
	 * @return
	 */
	@Bean
	public DataSourceTransactionManager transactitonManager(DataSource shardingDataSource) {
		return new DataSourceTransactionManager(shardingDataSource);
	}

	@Bean
	@Primary
	public SqlSessionFactory sqlSessionFactory(DataSource shardingDataSource) throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(shardingDataSource);
		bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
		return bean.getObject();
	}

	@Bean
	@Primary
	public SqlSessionTemplate testSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
		return new SqlSessionTemplate(sqlSessionFactory);
	}

	private Map<String, DataSource> createDataSourceMap() {
		Map<String, DataSource> result = new HashMap<>();
		result.put("user_0", createDataSource("user_0"));
		result.put("user_1", createDataSource("user_1"));
		return result;
	}

	private DataSource createDataSource(final String dataSourceName) {
		BasicDataSource result = new BasicDataSource();
		result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
		result.setUrl(String.format("jdbc:mysql://192.168.103.107:3306/%s", dataSourceName));
		result.setUsername("root");
		result.setPassword("tcbj");
		return result;
	}
}
